package mapa;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import objetoDeMapa.ObjetoDeMapa;
import matriz.Matriz;
import matriz.Iterador;
import celda.Celda;


public class Mapa {
	Matriz celdas;
	int dimension;
	
	public Mapa(int dimension) {

		this.dimension = dimension;	
		celdas = new Matriz(dimension, dimension);
		Iterador iterador = celdas.iterador();
		while (iterador.hasNext()) {
			iterador.set(new Celda());
		}		
		setearManzanas();
	}


	public Celda getCeldaEnPosicion(int fila, int columna) {
		return celdas.getElemento(fila, columna);
	}
	
	public void setearManzanas() {
		
		//Ciclo para ubicar la posicion de cada manzana
		for(int fila = 1; fila < dimension; fila += 3) {
			for(int columna = 1; columna < dimension; columna += 3) {				
				int finalFila = Math.min(2,dimension-fila);
				int finalColumna = Math.min(2,dimension-columna);
				
				//Ciclo para setear una manzana (4 celdas) en cada posicion
				for(int i = 0; i < finalFila; i++) {
					for(int j = 0; j < finalColumna; j++) {
						celdas.getElemento(fila + i, columna + j).setManzana();
					}
				}
			}
		}
	}

	public void actualizarVisibilidad(int fila, int columna) {
		
		//Calculo de limites para setear la visibilidad
		int inicialFila = Math.max(0, fila-2);
		int finalFila = Math.min(dimension, fila+3);
		int inicialColumna = Math.max(0, columna-2);
		int finalColumna = Math.min(dimension, columna+3);
		
		// Este ciclo setea visibilidad alrededor del punto (fila, columna)		
		for (int i = inicialFila; i < finalFila; i++) {
			for (int j = inicialColumna; j < finalColumna; j++) {
				this.getCeldaEnPosicion(i, j).cambiarVisibilidad();
			}
		}
	}

	public void agregarElementoEnPosicion(ObjetoDeMapa objetoDeMapa, int i, int j) {
		objetoDeMapa.setMapa(this);
		this.celdas.setElemento(i, j, Celda.conElemento(objetoDeMapa));
		
	}

	public int getDimension() {		
		return this.dimension;
	}

	public void remover(ObjetoDeMapa objetoDeMapa) {
		for(int fila = 0; fila < dimension; fila ++) {
			for(int columna = 0; columna < dimension; columna ++) {
				if (celdas.getElemento(fila, columna).getObjeto() == objetoDeMapa) {
					celdas.getElemento(fila, columna).removerContenido();
				}					
			}
		}
	}
	
	public Element serializar(org.w3c.dom.Document dom){
		Element mapaSerializado = dom.createElement("Mapa");
		
		Element NodoDimension = dom.createElement("dimension");
		NodoDimension.setTextContent(((Integer)this.dimension).toString());
		
		mapaSerializado.appendChild(NodoDimension);
		
		for(int fila = 0; fila < dimension; fila ++) {
			for(int columna = 0; columna < dimension; columna ++) {
				if (!celdas.getElemento(fila, columna).estaVacia()) {
					Posicion posicion = new Posicion(fila,columna);
					Node nodoPosicion = posicion.serializar(dom);
					
					Element nodoObjetoDeMapa = dom.createElement("ObjetoDeMapa");
					nodoObjetoDeMapa.setTextContent(celdas.getElemento(fila, columna).getObjeto().getClass().getName());
					
					nodoObjetoDeMapa.appendChild(nodoPosicion);
					mapaSerializado.appendChild(nodoObjetoDeMapa);
				}					
			}
		}
		
		return mapaSerializado;
	}
	
	public static Mapa deserializar(Node mapa) throws IllegalAccessException, ClassNotFoundException{
		
		Mapa nuevoMapa = null;
		
		Node nodoDimension = mapa.getChildNodes().item(1);
		nuevoMapa = new Mapa(Integer.parseInt(nodoDimension.getTextContent()));
		
		for(int i=0 ; i < mapa.getChildNodes().getLength(); i++)
		{
			Node nodo = mapa.getChildNodes().item(i);
			
			if(nodo.getNodeName() == "ObjetoDeMapa"){
				Object nuevoObjeoDeMapa = null;
				String nombre = nodo.getTextContent().replace(" ", "");
				nombre = nombre.replace("\n", "");
				try {
					nuevoObjeoDeMapa = Class.forName(nombre).newInstance();
					
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				Node nodoHijo = nodo.getChildNodes().item(1);
				Posicion posicion = Posicion.deserializar(nodoHijo);
				if(nuevoObjeoDeMapa!=null)
					nuevoMapa.agregarElementoEnPosicion((ObjetoDeMapa) nuevoObjeoDeMapa, posicion.getPosX(), posicion.getPosY());
			}
		}
		
		return nuevoMapa;
	}
}
